#include "ctrack_x.h"
#include "..\json\file_util.h"
#include <stdlib.h>
#include <stdio.h>

Generator::Generator(const char* dllFilePath)
{
	m_hDll = LoadLibraryA(dllFilePath);
	if (m_hDll == NULL) {
		m_sysError = GetLastError();
		m_state = -1;
		return;
	}

	m_fpTrackCreate = (FpTrackCreate)GetProcAddress(m_hDll, "TrackCreate");
	if(m_fpTrackCreate == NULL) {
		m_state = -2;
		return;
	}

	m_fpTrackStart = (FpTrackStart)GetProcAddress(m_hDll, "TrackStart");
	if(m_fpTrackStart == NULL) {
		m_state = -3;
		return;
	}

	m_fpTrackGo = (FpTrackGo)GetProcAddress(m_hDll, "TrackGo");
	if(m_fpTrackGo == NULL) {
		m_state = -4;
		return;
	}

	m_fpTrackRelease = (FpTrackRelease)GetProcAddress(m_hDll, "TrackRelease");
	if(m_fpTrackRelease == NULL) {
		m_state = -5;
		return;
	}

	m_state = 1;
}

Generator::~Generator()
{
	if(m_hDll != NULL) {
		FreeLibrary(m_hDll);
	}
}

int Generator::GetState(char info[], DWORD infoSize)
{
	switch(m_state) {
	case 1:
		sprintf_s(info, infoSize, "Load my \"%s\" ok", m_dllName);
		break;
	case -1:
		sprintf_s(info, infoSize, "Load my \"%s\" fails", m_dllName);
		break;
	case -2:
		sprintf_s(info, infoSize, "TrackCreate() not found in \"%s\"", m_dllName);
		break;
	case -3:
		sprintf_s(info, infoSize, "TrackStart() not found in \"%s\"", m_dllName);
		break;
	case -4:
		sprintf_s(info, infoSize, "TrackGo() not found in \"%s\"", m_dllName);
		break;
	case -5:
		sprintf_s(info, infoSize, "TrackRelease() not found in \"%s\"", m_dllName);
		break;
	default:
		break;
	}
	return(m_state);
}

DWORD Generator::TrackCreate(DVB dvArgs[])
{
	if(m_state == 1) {
		return((*m_fpTrackCreate)(dvArgs));
	} else {
		return(0);
	}
}

void Generator::TrackStart(DWORD hTrack, double v0)
{
	if(m_state == 1) {
		(*m_fpTrackStart)(hTrack, v0);
	}
}

WORD Generator::TrackGo(DWORD hTrack, double t, double pva[3])
{
	if(m_state == 1) {
		return((*m_fpTrackGo)(hTrack, t, pva));
	} else {
		return(0x00);
	}
}

void Generator::TrackRelease(DWORD hTrack)
{
	if(m_state == 1) {
		(*m_fpTrackRelease)(hTrack);
	}
}

MyTrack::MyTrack(Generator* pGenerator, DVB dvArgs[]): CTrack()
{
	m_pGenerator = pGenerator;
	m_hTrack = m_pGenerator->TrackCreate(dvArgs);
	m_bValid = TRUE;
	m_sva[0] = m_sva[1] = m_sva[2] = 0.0;
	m_bGoing = TRUE;
}

MyTrack::~MyTrack()
{
	m_pGenerator->TrackRelease(m_hTrack);
}

BOOL MyTrack::Joint(MotionContext *pmc)
{
	BOOL bJointOk = CTrack::Joint(pmc);
	m_pGenerator->TrackStart(m_hTrack, pmc->v);
	m_bGoing = TRUE;
	return(bJointOk);
}

int	MyTrack::GetNextPiece(double posiBuf[], double veloBuf[], double* pAcceBuf, DWORD markBuf[], DWORD maxTicks)
{
	if(!m_bValid || !m_bGoing) {
		return(0);
	}

	DWORD ticks = 0;
	for(DWORD i = 0; i < maxTicks; i++) {
		m_nextTick++;
		double t = DTIME(m_nextTick);
		WORD myMark = m_pGenerator->TrackGo(m_hTrack, t, m_sva);
		posiBuf[i] = m_nextCtx.p = m_jointCtx.p + m_sva[0];
		veloBuf[i] = m_nextCtx.v = m_sva[1];
		if(pAcceBuf != NULL) { pAcceBuf[i] = m_sva[2]; }

		DWORD dmark = 0x00000000;
		if(m_nextTick == 1) {
			dmark |= CTrack::START_MARK;
		}
		if(myMark & MY_TRACK_ERROR) {
			m_bValid = FALSE;
			dmark |= CTrack::END_MARK;
		}
		else if(myMark & MY_TRACK_END) {
			m_bGoing = FALSE;
			dmark |= CTrack::END_MARK;
		}

		if(myMark & MY_TRACK_TURN) {
			dmark |= CTrack::TURN_MARK;
		}
		if(myMark & MY_TRACK_HOLD) {
			dmark |= CTrack::HOLD_MARK;
		}
		
		DWORD userMark = (myMark & 0x000F);
		markBuf[i] = dmark | (userMark << 16);
	}
	return(ticks);
}
